package org.psyduck.security.config;

import cn.hutool.core.util.StrUtil;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.ssssssss.magicapi.controller.RequestHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;

public class PdAccessDecisionManager implements org.springframework.security.access.AccessDecisionManager {

    private final RequestMappingHandlerMapping requestMappingHandlerMapping;

    public PdAccessDecisionManager(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
    }

    @Override
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {

        FilterInvocation invocation = (FilterInvocation) object;
        HttpServletRequest request = invocation.getHttpRequest();
        Object handler = null;
        try {
            handler = requestMappingHandlerMapping.getHandler(request).getHandler();
        } catch (Exception ignored) {
        }
        if(handler != null && handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            if(RequestHandler.class == handlerMethod.getBean().getClass()){
                return;
            }
        }
        String token = StrUtil.blankToDefault(request.getHeader("token"),request.getParameter("token"));
        if (StrUtil.isNotBlank(token) && !token.equals("undefined")) {
            return;
        }
        if(configAttributes.stream().map(Object::toString).anyMatch(it -> it.equals("permitAll") || it.equals("anonymous"))){
            return;
        }
        throw new AccessDeniedException("Access is denied.");
    }
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}